package edu.map.aamas.gui;

import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.util.Vector;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;

import org.flexdock.docking.Dockable;
import org.flexdock.docking.DockingConstants;
import org.flexdock.docking.DockingManager;
import org.flexdock.docking.DockingPort;
import org.flexdock.util.SwingUtility;

import edu.map.aamas.charts.ActuationChart;
import edu.map.aamas.charts.AngularSpeedChart;
import edu.map.aamas.charts.ForceChart;
import edu.map.aamas.charts.HistogramChart;
import edu.map.aamas.charts.MeanSpeedChart;
import edu.map.aamas.charts.PositionChart;
import edu.map.aamas.charts.SpeedChart;
import edu.map.aamas.charts.TailAngleChart;
import edu.map.aamas.gui.docking.DockableSimpleInternalFrame;
import edu.map.aamas.gui.docking.MyDockingPort;
import edu.map.aamas.gui.docking.SimpleInternalFrame;
import edu.map.aamas.logging.RNNLogger;
import edu.map.aamas.rnn.RNN;

public class FlexPanel extends JApplet {
	
	public static JComponent createInterface() {
		return FlexPanel.createContentPane(true);
	}
	
	public static void main(String[] args) {

		boolean loaded = configureDocking();
		JFrame frame = new JFrame("Recurrent Neural Networks AAMAS project");
		frame.setContentPane(createContentPane(loaded));
		
		frame.setSize(800, 500);
		SwingUtility.centerOnScreen(frame);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setIconImage(createImageImpl("icons/brain.png"));
		frame.setVisible(true);
	}

	private static boolean configureDocking() {
		DockingManager.setFloatingEnabled(false);
		return false;
	}

	private static JComponent createContentPane(boolean loaded) {
		PondPanel pond = PondPanel.getInstance();
		RnnEvolutionDisplay evo = new RnnEvolutionDisplay();
		ConnectionMatrix conn = new ConnectionMatrix(RNN.getInstance());
		ActuationChart actuation = new ActuationChart(RNN.getInstance());
		AngularSpeedChart angSpeed = new AngularSpeedChart(RNN.getInstance());
		ForceChart force = new ForceChart(RNN.getInstance());
		MeanSpeedChart meanSpeed = new MeanSpeedChart(RNN.getInstance());
		TailAngleChart tailAngle = new TailAngleChart(RNN.getInstance());
		PositionChart pos = new PositionChart(RNN.getInstance());
		SpeedChart speed = new SpeedChart(RNN.getInstance());
		VarsCalibrationPanel calPanel = new VarsCalibrationPanel();
		HistogramChart hist = new HistogramChart(RNN.getInstance());
		
		MyDockingPort dockingPort = new MyDockingPort();
				
		Dockable dockPond = createFramePanel("Pond", pond, true, false);
		
		DockingManager.registerDockable(dockPond);
		DockingManager.dock(dockPond, (DockingPort) dockingPort, DockingConstants.CENTER_REGION);

		
		Dockable dockVars = createFramePanel("Variables", calPanel);
		DockingManager.registerDockable(dockVars);
		DockingManager.dock(dockVars, dockPond, DockingConstants.EAST_REGION, 0.5f);

		Dockable dockConn = createFramePanel("Connection Matrix", conn);
		DockingManager.registerDockable(dockConn);
		DockingManager.dock(dockConn, dockVars, DockingConstants.CENTER_REGION, 0.5f);

		
		Dockable dockEvo = createFramePanel("RNN evolution", evo);
		DockingManager.registerDockable(dockEvo);
		DockingManager.dock(dockEvo, dockConn, DockingConstants.CENTER_REGION, 0.5f);

		
		Dockable dockAct = createFramePanel("Actuation Chart", actuation);
		DockingManager.registerDockable(dockAct);
		DockingManager.dock(dockAct, dockPond, DockingConstants.SOUTH_REGION, 0.5f);

		Dockable dockForce = createFramePanel("Force Chart", force);
		DockingManager.registerDockable(dockForce);
		DockingManager.dock(dockForce, dockAct, DockingConstants.EAST_REGION, 0.5f);
		
		Dockable dockAngSpeed = createFramePanel("Angular Speed Chart", angSpeed);
		DockingManager.registerDockable(dockAngSpeed);
		DockingManager.dock(dockAngSpeed, dockConn, DockingConstants.SOUTH_REGION, 0.5f);
		
		//Dockable dockMeanSpeed = createFramePanel("Mean Speed Chart", meanSpeed);
		//DockingManager.registerDockable(dockMeanSpeed);
		//DockingManager.dock(dockMeanSpeed, dockAngSpeed, DockingConstants.EAST_REGION, 0.5f);

		Dockable dockSpeed = createFramePanel("Speed Chart", speed);
		DockingManager.registerDockable(dockSpeed);
		DockingManager.dock(dockSpeed, dockAngSpeed, DockingConstants.EAST_REGION, 0.5f);
		
		Dockable dockTailAng = createFramePanel("Tail Angle Chart", tailAngle);
		DockingManager.registerDockable(dockTailAng);
		DockingManager.dock(dockTailAng, dockSpeed, DockingConstants.SOUTH_REGION, 0.5f);

		//Dockable dockPos = createFramePanel("Position Chart", pos);
		//DockingManager.registerDockable(dockPos);
		//DockingManager.dock(dockPos, dockAngSpeed, DockingConstants.SOUTH_REGION, 0.5f);

		Dockable dockHist = createFramePanel("Histogram", hist);
		DockingManager.registerDockable(dockHist);
		DockingManager.dock(dockHist, dockAngSpeed, DockingConstants.SOUTH_REGION, 0.5f);

		RNN.getInstance().addRnrListener(pond);
		RNN.getInstance().addRnrListener(actuation);
		RNN.getInstance().addRnrListener(force);
		RNN.getInstance().addRnrListener(evo);
		RNN.getInstance().addRnrListener(meanSpeed);
		RNN.getInstance().addRnrListener(angSpeed);
		RNN.getInstance().addRnrListener(pos);
		RNN.getInstance().addRnrListener(tailAngle);
		RNN.getInstance().addRnrListener(speed);
		RNN.getInstance().addRnrListener(new RNNLogger());
		RNN.getInstance().init();
		RNN.getInstance().resume();
		
		JPanel p = new JPanel(new BorderLayout());
		p.add(new ControlPanel(RNN.getInstance()), BorderLayout.NORTH);
		p.add(dockingPort, BorderLayout.CENTER);
		return p;
	}

	private static Dockable createFramePanel(String title, JComponent internalComp) {
		return createFramePanel(title, internalComp, true, true);
	}
	
	private static Dockable createFramePanel(String title, JComponent internalComp, boolean maximizable, boolean closeable) {
		
		final JButton maxButton = createButton(createIcon("icons/maximize.png"));
		maxButton.setToolTipText("Maximize");
		final JButton closeButton = createButton(createIcon("icons/cancel.png"));
		closeButton.setToolTipText("Close");
		maxButton.setMargin(new Insets(0,0,0,0));
		closeButton.setMargin(new Insets(0,0,0,0));
		
		Vector<JButton> btns = new Vector<JButton>();
		if (maximizable)
			btns.add(maxButton);
		if (closeable)
			btns.add(closeButton);
		
		JToolBar toolbar = createPortletToolbar(btns.toArray(new JButton[]{}));

		SimpleInternalFrame sif = new SimpleInternalFrame(title, toolbar, internalComp);
		final Dockable dockable = new DockableSimpleInternalFrame(sif);

		maxButton.addActionListener(new ActionListener() {
			private boolean minimized = false;
			public void actionPerformed(ActionEvent e) {
				DockingManager.toggleMaximized(dockable);
				if (!minimized) {
					maxButton.setIcon(createIcon("icons/minimize.png"));
					maxButton.setToolTipText("Minimize");
					minimized = true;
				}
				else {
					maxButton.setIcon(createIcon("icons/maximize.png"));
					maxButton.setToolTipText("Maximize");
					minimized = false;					
				}
			}
		});
		
		closeButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				DockingManager.close(dockable);
				try {
					DockingManager.storeLayoutModel();
				}
				catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		
		});


		return dockable;
	}

	private static JButton createButton(Icon icon) {
		JButton button = new JButton(icon);
		button.setFocusable(false);
		return button;
	}

	private static JToolBar createPortletToolbar(JButton[] buttons) {
		JToolBar toolbar = new JToolBar();
		for (JButton btn : buttons)
			toolbar.add(btn);
		toolbar.setFloatable(false);
		toolbar.putClientProperty("JToolBar.isRollover", Boolean.TRUE);

		return toolbar;
	}

	private static Icon createIcon(String icon) {
		return new ImageIcon(createImageImpl(icon));
	}

	private static Image createImageImpl(String resourceName) {
		URL iconURL = FlexPanel.class.getClassLoader().getResource(resourceName);
		if (iconURL == null) {
			throw new RuntimeException("Could not find: " + resourceName);
		}
		return Toolkit.getDefaultToolkit().createImage(iconURL);
	}

	
	@Override
	public void init() {
		super.init();
		this.setLayout(new BorderLayout());
		getContentPane().add(createContentPane(true));
		RNN.getInstance().init();
	}
	
	@Override
	public void stop() {
		super.stop();
		RNN.getInstance().pause();
	}
	
	@Override
	public void start() {
		RNN.getInstance().resume();
	}
}